﻿namespace Sofire.Data
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Text;

    using Sofire.Dynamic.Factories;

    /// <summary>
    /// 表示一个动态映射的实体集合。
    /// </summary>
    /// <typeparam name="TEntity">映射的实体类型。</typeparam>
    public partial class DynamicEntityCollection<TEntity>
        where TEntity : new()
    {
        #region Fields

        /// <summary>
        /// 表示当前集合的同步对象。
        /// </summary>
        protected readonly object SyncObject = new object();

        /// <summary>
        /// 表示动态实体集合的实体列表。
        /// </summary>
        protected EntityCollection _entities;

        /// <summary>
        /// 表示集合是否正在操作数据行。
        /// </summary>
        protected bool _IsCollectionChangedRow;

        /// <summary>
        /// 表示动态实体集合的数据行列表。
        /// </summary>
        protected List<DataRow> _rows;

        /// <summary>
        /// 表示动态实体的源表。
        /// </summary>
        protected DataTable _table;

        #endregion Fields

        #region Events

        /// <summary>
        /// 当集合的实体改变后发生。
        /// </summary>
        public event EntityChangedEventHandler EntityChanged;

        #endregion Events

        #region Properties

        /// <summary>
        /// 获取一个值，表示集合是否正在操作数据行。
        /// </summary>
        public bool IsCollectionChangedRow
        {
            get { return this._IsCollectionChangedRow; }
        }

        /// <summary>
        /// 表示实体的映射。
        /// </summary>
        protected readonly IEntityMapper EntityMapping;

        /// <summary>
        /// 表示数据行的映射。
        /// </summary>
        protected readonly IRowMapper RowMapping;

        #endregion Properties

        #region Methods

        /// <summary>
        /// 引发 Sofire.Data.DynamicEntityCollection&lt;TEntity&gt;.EntityChanged 事件。
        /// </summary>
        /// <param name="operation">实体操作类型。</param>
        /// <param name="row">影响的数据行。</param>
        protected virtual void OnEntityChanged(EntityOperation operation, DataRow row)
        {
            if(this.EntityChanged != null)
                this.EntityChanged(this, new EntityChangedEventArgs(operation, row));
        }

        #endregion Methods
    }

    public partial class DynamicEntityCollection<TEntity>
    {
        #region Constructors

        /// <summary>
        /// 指定动态映射的源表，初始化 <see cref="Sofire.Data.DynamicEntityCollection&lt;TEntity&gt;"/> 类的新实例。
        /// </summary>
        /// <param name="table">映射的源表。</param>
        public DynamicEntityCollection(DataTable table)
            : this(table.Rows.Count)
        {
            if(table == null) throw new ArgumentNullException("table");
            this._table = table;

            var rows = table.Rows;
            int rowCount = rows.Count;
            var entityType = typeof(TEntity);
            this.EntityMapping = EntityMapper.Create(entityType);
            this.RowMapping = RowMapper.Create(entityType);
            if(rowCount > 0)
            {
                TEntity entity;

                foreach(DataRow row in table.Rows)
                {
                    entity = new TEntity();
                    this.EntityMapping.FillEntity(row, entity);
                    this._rows.Add(row);
                    this._entities.Add(entity);
                }
            }
        }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.DynamicEntityCollection&lt;TEntity&gt;"/> 类的新实例，该实例为空并且具有指定的初始容量。
        /// </summary>
        /// <param name="capacity">新列表最初可以存储的元素数。</param>
        private DynamicEntityCollection(int capacity)
        {
            this._rows = new List<DataRow>(capacity);
            this._entities = new EntityCollection(this, capacity);
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// 获取当前集合的实体数。
        /// </summary>
        public int Count
        {
            get { return this._entities.Count; }
        }

        #endregion Properties

        #region Indexers

        /// <summary>
        /// 获取指定索引处的实体。
        /// </summary>
        /// <param name="index">要获得的实体从零开始的索引。</param>
        /// <returns>返回指定索引处的实体。</returns>
        public TEntity this[int index]
        {
            get
            {
                return this._entities[index];
            }
        }

        /// <summary>
        /// 获取指定数据行处的实体。
        /// </summary>
        /// <param name="row">映射的数据行。</param>
        /// <returns>返回指定数据行处的实体。</returns>
        public TEntity this[DataRow row]
        {
            get
            {
                int index = row == null ? -1 : this._rows.IndexOf(row);
                if(index == -1)
                    return default(TEntity);
                return this._entities[index];
            }
        }

        /// <summary>
        /// 获取指定实体处的数据行。
        /// </summary>
        /// <param name="entity">映射的实体。</param>
        /// <returns>返回指定实体处的数据行。</returns>
        public DataRow this[TEntity entity]
        {
            get
            {
                int index = entity == null ? -1 : this._entities.IndexOf(entity);
                if(index == -1)
                    return null;
                return this._rows[index];
            }
        }

        #endregion Indexers
    }

    public partial class DynamicEntityCollection<TEntity>
    {
        #region Methods

        /// <summary>
        /// 清空当前集合和源表的所有数据。
        /// </summary>
        public void Clear()
        {
            lock(this.SyncObject)
            {
                this._IsCollectionChangedRow = true;

                this._rows.Clear();
                this._entities.Clear();
                this._table.Clear();

                this.OnEntityChanged(EntityOperation.Clear, null);

                this._IsCollectionChangedRow = false;
            }
        }

        #region Delete

        /// <summary>
        /// 将指定的数据行和实体从当前集合移除。
        /// </summary>
        /// <param name="row">映射的数据行。</param>
        /// <param name="entity">映射的实体。</param>
        /// <returns>如果移除成功则返回 true，否则返回 false。</returns>
        private bool Delete(DataRow row, TEntity entity)
        {
            lock(this.SyncObject)
            {
                this._IsCollectionChangedRow = true;

                bool result = this._rows.Remove(row) && this._entities.Remove(entity);
                if(result)
                {
                    row.Delete();
                    this.OnEntityChanged(EntityOperation.Delete, row);
                }
                this._IsCollectionChangedRow = false;
                return result;
            }
        }

        /// <summary>
        /// 将指定的实体从当前集合移除。
        /// </summary>
        /// <param name="entity">映射的实体。</param>
        /// <returns>如果移除成功则返回 true，否则返回 false。</returns>
        public bool Delete(TEntity entity)
        {
            return this.Delete(this[entity], entity);
        }

        /// <summary>
        /// 移除当前集合指定索引的项。
        /// </summary>
        /// <param name="index">从零开始的索引。</param>
        /// <returns>如果移除成功则返回 true，否则返回 false。</returns>
        public bool DeleteAt(int index)
        {
            return this.Delete(this._rows[index], this._entities[index]);
        }

        #endregion

        #region Insert

        /// <summary>
        /// 为指定的实体创建一个数据行，并添至当前集合的末尾处。
        /// </summary>
        /// <param name="entity">映射的实体。</param>
        /// <returns>返回新创建的数据行。</returns>
        public DataRow Insert(TEntity entity)
        {
            return this.Insert(entity, -1);
        }

        /// <summary>
        /// 为指定的实体创建一个数据行，并添至当前集合指定的索引处。
        /// </summary>
        /// <param name="entity">映射的实体。</param>
        /// <param name="index">从零开始的索引，应在该位置插入项。</param>
        /// <returns>返回新创建的数据行。</returns>
        public DataRow Insert(TEntity entity, int index)
        {
            var row = this.CreateRow(entity);
            this.Insert(row, entity, index);
            return row;
        }

        /// <summary>
        /// 将指定的数据行和实体添加到当前集合指定的索引处。
        /// </summary>
        /// <param name="row">映射的数据行。</param>
        /// <param name="entity">映射的实体。</param>
        /// <param name="index">从零开始的索引，应在该位置插入项。</param>
        protected virtual void Insert(DataRow row, TEntity entity, int index)
        {
            lock(this.SyncObject)
            {
                this._IsCollectionChangedRow = true;
                if(index == -1)
                {
                    this._rows.Add(row);
                    this._entities.Add(entity);
                }
                else
                {
                    this._rows.Insert(index, row);
                    this._entities.Insert(index, entity);
                }
                this._IsCollectionChangedRow = false;
                this.OnEntityChanged(EntityOperation.Insert, row);
            }
        }

        #endregion

        /// <summary>
        /// 为指定的实体创建一个数据行，并创建的数据行添至源表的末尾处。
        /// </summary>
        /// <param name="entity">映射的实体。</param>
        /// <returns>返回新创建的数据行。</returns>
        protected virtual DataRow CreateRow(TEntity entity)
        {
            lock(this.SyncObject)
            {
                this._IsCollectionChangedRow = true;
                DataRow row = this._table.NewRow();
                this.RowMapping.FillRow(entity, row);
                this._table.Rows.Add(row);
                this._IsCollectionChangedRow = false;
                return row;
            }
        }

        /// <summary>
        /// 将所有的实体的数据，填充到数据行（*并非保存到数据库）。
        /// </summary>
        public virtual void Update()
        {
            this._IsCollectionChangedRow = true;
            this._table.BeginLoadData();
            for(int i = 0 ; i < this._entities.Count ; i++)
            {
                this.RowMapping.FillRow(this._entities[i], this._rows[i]);
            }
            this._table.EndLoadData();
            this._IsCollectionChangedRow = false;
        }

        #endregion Methods
    }

    public partial class DynamicEntityCollection<TEntity>
    {
        #region Nested Types

        /// <summary>
        /// 表示动态集合的实体列表。
        /// </summary>
        protected class EntityCollection : List<TEntity>, IList
        {
            #region Fields

            DynamicEntityCollection<TEntity> _collection;

            #endregion Fields

            #region Constructors

            /// <summary>
            /// 初始化 <see cref="Sofire.Data.DynamicEntityCollection&lt;TEntity&gt;.EntityCollection"/> 类的新实例。
            /// </summary>
            /// <param name="collection">附属的集合。</param>
            /// <param name="capacity">新列表最初可以存储的元素数。</param>
            public EntityCollection(DynamicEntityCollection<TEntity> collection, int capacity)
                : base(capacity)
            {
                this._collection = collection;
            }

            #endregion Constructors

            #region Methods

            /// <summary>
            /// 将某项添加到 System.Collections.IList 中。
            /// </summary>
            /// <param name="value">要添加到 System.Collections.IList 的 System.Object。</param>
            /// <returns>新元素的插入位置。</returns>
            int IList.Add(object value)
            {
                this._collection.Insert((TEntity)value);
                return this.Count - 1;
            }

            /// <summary>
            /// 从 System.Collections.IList 中移除所有项。
            /// </summary>
            void IList.Clear()
            {
                this._collection.Clear();
            }

            /// <summary>
            /// 将一个项插入指定索引处的 System.Collections.IList。
            /// </summary>
            /// <param name="index">从零开始的索引，应在该位置插入 value。</param>
            /// <param name="value">要插入 System.Collections.IList 中的 System.Object。</param>
            void IList.Insert(int index, object value)
            {
                this._collection.Insert((TEntity)value, index);
            }

            /// <summary>
            /// 从 System.Collections.IList 中移除特定对象的第一个匹配项。
            /// </summary>
            /// <param name="value">要从 System.Collections.IList 移除的 System.Object。</param>
            void IList.Remove(object value)
            {
                this._collection.Delete((TEntity)value);
            }

            /// <summary>
            /// 移除指定索引处的 System.Collections.IList 项。
            /// </summary>
            /// <param name="index">从零开始的索引（属于要移除的项）。</param>
            void IList.RemoveAt(int index)
            {
                this._collection.DeleteAt(index);
            }

            int ICollection.Count
            {
                get
                {
                    return this._collection.Count;
                }
            }

            #endregion Methods
        }

        #endregion Nested Types
    }

    public partial class DynamicEntityCollection<TEntity> : IEnumerable<TEntity>, IListSource, IDisposable
    {
        #region Fields

        private bool _IsDisposed;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// 析构方法。
        /// </summary>
        ~DynamicEntityCollection()
        {
            this.Dispose();
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// 获取表示集合是否是 System.Collections.IList 对象集合的值。
        /// </summary>
        [Browsable(false)]
        public bool ContainsListCollection
        {
            get { return this._entities != null; }
        }

        /// <summary>
        /// 指示当前对象是否已被释放。
        /// </summary>
        [Browsable(false)]
        public bool IsDisposed
        {
            get { return this._IsDisposed; }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// 释放由 Sofire.Data.DynamicEntityCollection&lt;TEntity&gt; 使用的所有资源。
        /// </summary>
        public void Dispose()
        {
            if(this._IsDisposed)
                return;
            this._IsDisposed = true;
            this.Disposing();
        }

        /// <summary>
        /// 返回循环访问 Sofrire.Data.DynamicEntityCollection&lt;TEntity&gt; 的枚举数。
        /// </summary>
        /// <returns>返回枚举的 System.Collections.Generic.IEnumerator&lt;TEntity&gt;。</returns>
        public IEnumerator<TEntity> GetEnumerator()
        {
            return this._entities.GetEnumerator();
        }

        /// <summary>
        /// 从不实现 System.Collections.IList 本身的对象返回可以绑定到数据源的 System.Collections.IList。
        /// </summary>
        public IList GetList()
        {
            return this._entities;
        }

        /// <summary>
        /// 返回一个循环访问集合的枚举数。
        /// </summary>
        /// <returns>可用于循环访问集合的 System.Collections.IEnumerator 对象。</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)this._entities).GetEnumerator();
        }

        /// <summary>
        /// 释放当前 Sofire.Data.DynamicEntityCollection&lt;TEntity&gt; 对象。
        /// </summary>
        protected virtual void Disposing()
        {
            if(this._entities != null)
                this._entities.Clear();
            if(this._rows != null)
                this._rows.Clear();
            if(this._table != null)
            {
                this._table.Rows.Clear();
                this._table.Dispose();
                this._table = null;
            }
            //GC.SuppressFinalize(this);
        }

        #endregion Methods
    }
}